#include "memorypool.h"
#include <atomic>
#include <new>

using std::lock_guard;
using std::memory_order_relaxed;
using std::memory_order_acquire;
using std::memory_order_release;

namespace memorypool
{   
    
    MemoryPool::MemoryPool(size_t BlockSize)
    :_blockSize(BlockSize)
    ,_slotSize(0)
    ,_freeListPtr(nullptr)
    ,_firstUnusedSlot(nullptr)
    ,_firstBlock(nullptr)
    ,_lastSlotPtr(nullptr)
    {}

    MemoryPool::~MemoryPool() {
        // 首先获取第一个Block
        Slot* tmp = _firstBlock;
        while(tmp) {
            // 先保存下一个Block的起始地址
            Slot* nextBlock = tmp->next;
            // 调用operator delete
            operator delete(reinterpret_cast<void*>(tmp));
            // 然后走到下一个block
            tmp = nextBlock;
        }
    }
    
    void MemoryPool::init(size_t slotSize) {
        _slotSize = slotSize;
        _freeListPtr = nullptr;
        _firstUnusedSlot = nullptr;
        _firstBlock = nullptr;
        _lastSlotPtr = nullptr;
    }

    void* MemoryPool::allocate() {
        // 先从使用过已归还的链表中获取
        Slot* result = popFreeListSlot();
        if (result != nullptr) {
            // 说明获取到一个Slot
            return result;
        }

        // 到这里说明归还链表中没有多的，没有获取到
        {
            // 创建lock_guard对象并自动加锁
            lock_guard<mutex> _lock(_forBlockMutex);

            if (_firstUnusedSlot >= _lastSlotPtr) {
                // 说明Block不够了，需要再次申请一块
                allocateNewBlock();
            }
            // 直接将当前第一个未使用的slot交给result返回
            result = _firstUnusedSlot;
            _firstUnusedSlot += _slotSize / sizeof(Slot);
        }
        return result;
    }

    void MemoryPool::deallocate(void *ptr) {
        if (!ptr) {
            // ptr为空时则直接返回
            return;
        }
        // 强转后加到归还链表中
        Slot* slot = reinterpret_cast<Slot*>(ptr);
        pushSlotToFreeList(slot);
    }

    void MemoryPool::allocateNewBlock() {

        // 调用operator new分配一片新的块
        void* newBlockPtr = operator new(_blockSize);
        // 采用头插法将其加到当前内存池的Block链表中
        reinterpret_cast<Slot*>(newBlockPtr)->next = _firstBlock;
        _firstBlock = reinterpret_cast<Slot*>(newBlockPtr);
        // 将newBlockPtr往后移动sizeof(Slot*)个字节
        char* padStartPtr = reinterpret_cast<char*>(newBlockPtr) + sizeof(Slot*);
        // 获取与slot对齐需要填充的字节数
        size_t padSizes = padPointer(padStartPtr, _slotSize);
        // 更新第一个未使用的slot指针
        _firstUnusedSlot = reinterpret_cast<Slot*>(padStartPtr + padSizes);

        // _lastSlotPtr的值就是当前Block中最后一个可用Slot的末尾地址
        _lastSlotPtr = reinterpret_cast<Slot*>(reinterpret_cast<char*>(newBlockPtr) + _blockSize);
    }

    size_t MemoryPool::padPointer(char *p, size_t align) {
        // reinterpret_cast<size_t>(p) % align计算出来的值表示p相对上一个slot对齐
        // 的地址多了几个字节
        return align - (reinterpret_cast<size_t>(p) % align);
    }


    bool MemoryPool::pushSlotToFreeList(Slot* slot) {
        while(true) {
            // 先读取一个旧的值
            Slot* oldHead = _freeListPtr.load(memory_order_relaxed);

            // 对Slot结构体中的next进行存储
            slot->next.store(oldHead, memory_order_relaxed);

            if (_freeListPtr.compare_exchange_weak(oldHead, slot, memory_order_release, memory_order_relaxed)) {
                return true;
            }
            // 失败的话则说明另一个线程修改了_freeListPtr
            // 那么这个时候就重新循环
        }
    }


    Slot* MemoryPool::popFreeListSlot() {
        while(true) {
            // 首先还是取出旧的头
            Slot* oldHead = _freeListPtr.load(memory_order_relaxed);
            if (oldHead == nullptr) {
                return nullptr;
            }
            // 然后因为这里是头删，所以获取新的头
            Slot* newHead = nullptr;
            try {
                // 获取新的头
                newHead = oldHead->next.load(memory_order_relaxed);
            } catch (...) {
                // 重试
                continue;
            }
            if (_freeListPtr.compare_exchange_weak(oldHead, newHead, memory_order_acquire, memory_order_relaxed)) {
                return oldHead;
            }
        }
    }

    void HashBucket::initMemory() {
        for (int i = 0; i < MEMORY_POOL_NUMS; ++i) {
            // 总共需要初始化MEMORY_POOL_NUMS个小内存池
            getMemory(i).init((i + 1) * BASIC_SLOT_SIZE);
        }
    }

    MemoryPool& HashBucket::getMemory(int index) {
        // 定义一个MemoryPool的数组
        static MemoryPool memorypools[MEMORY_POOL_NUMS];
        return memorypools[index];
    }

    void* HashBucket::useMemory(size_t size) {
        if (size <= 0) {
            return nullptr;
        } 
        if (size >= MAX_SLOT_SIZE) {
            // 超过512的话就使用operator new进行内存分配
            return operator new(size);
        }
        // 到这里说明不超过512
        return getMemory((size + 7) / BASIC_SLOT_SIZE - 1).allocate();
    }


    void HashBucket::freeMemory(void* ptr, size_t size) {
        if (ptr == nullptr) {
            return;
        }
        // 当超过512时，使用系统的operator delete进行释放
        if (size >= MAX_SLOT_SIZE) {
            operator delete(ptr);
            return;
        }
        // 否则就使用内存池的释放函数
        getMemory((size + 7) / BASIC_SLOT_SIZE - 1).deallocate(ptr);
    }

}